# Advanced TeX snippets powered by ultisnip
# vim: set noexpandtab:

# seealso :help snippet-options

global !p
def slugify(text):
    try:
        import unidecode
        text = unidecode.unidecode(text)
    except ModuleNotFoundError:
        pass
    import re
    return re.sub(r'[\W_]+', '-', text.lower())

def get_matching_pair(query):
    pairs = ['()', '{}', '<>', '[]' ]
    d = dict(sum([[(l, r), (r, l)] for (l, r) in pairs], []))
    # find a matching pair based on the first character.
    return d.get(query[0], "") if query else ""
endglobal


# Reference:
# https://vi.stackexchange.com/questions/18490/ultisnips-context-and-tex
# https://castel.dev/post/lecture-notes-1/
global !p

# Note: "is_math()" requires 'e' snippet qualifier
def is_math():
    if vim.eval('get(b:, "ts_highlight")'):
        return int(vim.eval('luaeval("require \'lib.latex\'.in_mathzone() and 1 or 0")')) > 0
    else:
        return int(vim.eval('vimtex#syntax#in_mathzone()')) > 0

def detect_root_texfile():
    from glob import glob
    import os.path
    import re
    file_path = os.path.realpath(vim.eval("expand('%:p:h')"))
    for f in glob(os.path.join(vim.eval("getcwd()"), "*.tex")):
        with open(f, "r") as fp:
            for nr, line in enumerate(fp):
                if nr > 50: break   # do not read too many lines
                if re.match(r'%\s!\s*TEX root\s*=\s*', line, re.IGNORECASE):
                    continue
                if line.startswith(r'\documentclass'):
                    f = os.path.realpath(f)
                    return os.path.relpath(f, start=file_path)
    return "UNKNOWN_ROOT_DOCUMENT.tex"  # Not found
endglobal

# ===================
# Preamble
# ===================

snippet "%! TEX root" "Inserts `%! TEX root = ...` directive"
%! TEX root = `!p snip.rv = detect_root_texfile()`
endsnippet
snippet hyperref "Import hyperref package with color settings."
\usepackage[pagebackref=true,breaklinks=true,colorlinks,bookmarks=false]{hyperref}
\hypersetup{linkcolor=red,citecolor=green,urlcolor=magenta,menucolor=red}
endsnippet
snippet lineno "Adds line numbers for draft mode."
\usepackage{lineno}
\linenumbers
% Patch per https://tex.stackexchange.com/questions/25784/
\let\oldalign\align \let\oldendalign\endalign
\renewenvironment{align}{\linenomathNonumbers\oldalign}{\oldendalign\endlinenomath}
endsnippet

snippet argmin "Define \argmin"
\newcommand{\argmin}{\operatornamewithlimits{argmin}}
endsnippet
snippet argmax "Define \argmax"
\newcommand{\argmax}{\operatornamewithlimits{argmax}}
endsnippet
snippet norm "Define \norm command"
\newcommand\norm[1]{\left\lVert#1\right\rVert}
endsnippet
snippet tightlist "Define \tightlist"
\providecommand{\tightlist}{\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
endsnippet
snippet xspace "Import xspace package and configure it"
\usepackage{xspace}
\xspaceaddexceptions{]\\}}
endsnippet
snippet cleveref "Import cleveref package"
\usepackage[nameinlink,capitalize,noabbrev]{cleveref}
endsnippet
snippet def.todo "Define \todo macro"
\newcommand{\\${1:todo}}[1]{\mbox{\color{red}{\small\bf\sf [${2:TODO: }#1]}}}
endsnippet
snippet def.abbr "Define \eg, \ie, \etal, \etc abbrs"
\newcommand{\eg}{\emph{e.g.}\@\xspace}
\newcommand{\ie}{\emph{i.e.}\@\xspace}
\newcommand{\etal}{\emph{et al.}\@\xspace}
\makeatletter
\newcommand*{\etc}{\@ifnextchar{.}%
	{\emph{etc}}%
	{\emph{etc.}\@\xspace}%
}\makeatother
endsnippet
snippet defparagraph "Redefine \paragraph to allow configuration of margins around"
\makeatletter
\renewcommand{\paragraph}{%
	\@startsection{paragraph}{4}%
	{\z@}{${1:1.0ex} \@plus ${2:0.50ex} \@minus ${3:0.20ex}}{-1em}%
	{\normalfont\normalsize\bfseries}%
}
\makeatother
endsnippet

# ================================
# General text styles
# ================================

snippet bf
{\bf ${1}}$0
endsnippet
snippet it
{\it ${1}}$0
endsnippet
snippet sf
{\sf ${1}}$0
endsnippet
snippet emph
\emph{${1}}$0
endsnippet
snippet tbf
\textbf{${1}}$0
endsnippet
snippet textbf
\textbf{${1}}$0
endsnippet
snippet tit
\textit{${1}}$0
endsnippet
snippet textit
\textit{${1}}$0
endsnippet
snippet tsf
\textsf{${1}}$0
endsnippet
snippet textsf
\textsf{${1}}$0
endsnippet
snippet mbf
\mathbf{${1}}$0
endsnippet
snippet mathbf
\mathbf{${1}}$0
endsnippet
snippet mrm
\mathrm{${1}}$0
endsnippet
snippet mathrm
\mathrm{${1}}$0
endsnippet


# ===================
# Common environments
# ===================

# \newenvironment{<env-name>}[<n-args>][<default>]{<begin-code>}{<end-code>}
snippet newenvironment "Define a new environment"
\newenvironment{${1:envname}}${2:[nargs]}{begin-code}{end-code}
endsnippet

# section and subsection
# \sec, \section, sec, section, etc.
# ----------------------------------

snippet "\\?sec(tion)?" "\section{}" rb
\section{$1}
\label{sec:`!p snip.rv = slugify(t[1])`}
$0
endsnippet
snippet "\\?subsec(tion)?" "\subsection{}" rb
\subsection{$1}
\label{sec:`!p snip.rv = slugify(t[1])`}
$0
endsnippet
snippet "\\?para(graph)?" "\paragraph{}" wr
\paragraph{${1}} $0
endsnippet
snippet "\\?left" "\left..\right" r
\left${1:}\right`!p snip.rv = get_matching_pair(t[1])`
endsnippet

# math mode snippets (e: custom context)
# -------------------------------------
# wAe means -- w: word boundary, A: Automatic trigger, e: custom context (:h Ultisnips-snippet-options)
# Note: ultisnips syntax is currently wrong, which needs to be fixed (see SirVer/ultisnips#1463)

snippet cal "\mathcal" "is_math()" wAe
\mathcal{$1}$0
endsnippet
snippet bf "\mathbf" "is_math()" wAe
\mathbf{$1}$0
endsnippet
snippet bb "\mathbb" "is_math()" wAe
\mathbb{$1}$0
endsnippet

snippet -> "\rightarrow" "is_math()" wAe
\rightarrow
endsnippet
snippet <- "\leftarrow" "is_math()" wAe
\leftarrow
endsnippet
snippet => "\Rightarrow" "is_math()" wAe
\Rightarrow
endsnippet
snippet <= "\Leftarrow" "is_math()" wAe
\Leftarrow
endsnippet
snippet ==> "\Longrightarrow" "is_math()" wAe
\Longrightarrow
endsnippet
snippet <== "\Longleftarrow" "is_math()" wAe
\Longleftarrow
endsnippet

# automatic subscript and superscript
snippet _t+1 "_{t+1}" "is_math()" iAe
_{t+1}
endsnippet
snippet _t-1 "_{t-1}" "is_math()" iAe
_{t-1}
endsnippet
snippet '([a-z])\(i\)' "^{(i)}" "is_math()" ireA
`!p snip.rv = match.group(1)`^{(i)}
endsnippet
snippet '([A-Za-z])(\d)' "x1 -> x_1" "is_math()" wreA
`!p snip.rv = match.group(1)`_`!p snip.rv = match.group(2)`
endsnippet
snippet '([A-Za-z])_(\d\d)' "x_12 -> x_{12}" "is_math()" wreA
`!p snip.rv = match.group(1)`_{`!p snip.rv = match.group(2)`}
endsnippet
snippet '([A-Za-z])_([a-z][a-z])' "x_ij -> x_{ij}" "is_math()" wreA
`!p snip.rv = match.group(1)`_{`!p snip.rv = match.group(2)`}
endsnippet
snippet ^( "^{(...)}" "is_math()" iAe
^{($1)}$0
endsnippet

# Use \mid instead of | in probability distributions

# Manual triggers: \left..\right pairs for {} [] () <>
snippet l "left" "is_math()" e
\left
endsnippet
snippet r "right" "is_math()" e
\right
endsnippet
snippet { "Curly braces" "is_math()" e
\left\\{ ${1} \right\\}$0
endsnippet
snippet [ "Square bracket" "is_math()" e
\left[ ${1} \right]$0
endsnippet
snippet ( "Parenthesis" "is_math()" e
\left( ${1} \right)$0
endsnippet
snippet < "Angle" "is_math()"  e
\left\langle ${1} \right\rangle$0
endsnippet

# Automatic triggers for \left..\right {} [] () <>
snippet \{ "{...}" "is_math()" eA
\left\\{ ${1} \right\\}$0
endsnippet
snippet \( "(...)" "is_math()" eA
\left( ${1} \right)$0
endsnippet
snippet \[ "[...]" "is_math()" eA
\left[ ${1} \right]$0
endsnippet
snippet \< "<...>" "is_math()" eA
\left\langle ${1} \right\rangle$0
endsnippet

# Automatic fraction.  something/ -> \frac{something}{}
# To use '/' literally, have a whitespace around it (e.g. something /)
# Reference: https://castel.dev/post/lecture-notes-1
snippet '((\d+)|(\d*)(\\)?([A-Za-z]+)((\^|_)(\{\d+\}|\d))*)/' "Fraction" "is_math()" wreA
\\frac{`!p snip.rv = match.group(1)`}{$1}$0
endsnippet

# Very common expressions and idoms
snippet sumi "Sigma i=0" "is_math()" wAe
\sum_{i=1}^{$2}$0
endsnippet
snippet E "Expectation" "is_math()" e
{\mathbb E}_{${1:condition}} \left[ $2 \right]$0
endsnippet

# ===================
# Environment Blocks
# ===================
snippet $$ "Math equation block"
$$
	$0
$$
endsnippet
snippet \[ "Math equation block"
\[
	$0
\]
endsnippet
snippet \begin "\begin{} ... \end{} block"
\begin{${1:env}}
	${0}
\end{$1}
endsnippet
snippet begin "\begin{} ... \end{} block"
\begin{${1:env}}${0}
\end{$1}
endsnippet
snippet a "\begin{align} ... \end{align} block"
\begin{align}
	${0}
\end{align}
endsnippet
snippet align "\begin{align} ... \end{align} block"
\begin{align}
	${0}
\end{align}
endsnippet
snippet align* "\begin{align*} ... \end{align*} block"
\begin{align*}
	${0}
\end{align*}
endsnippet
snippet aligned "\begin{aligned} ... \end{aligned} block"
\begin{aligned}
	${0}
\end{aligned}
endsnippet
snippet flalign "\begin{flalign} ... \end{flalign} block"
\begin{flalign}
	${0}
\end{flalign}
endsnippet
snippet tcolorbox "\begin{tcolorbox} ... \end{tcolor} block (requires package tcolorbox)"
\begin{tcolorbox}[title=$1,colback=red!10!white,colframe=red!70!black]
	${0}
\end{tcolorbox}
endsnippet
snippet center "\begin{center} ... \end{center} block"
\begin{center}
	${0}
\end{center}
endsnippet
snippet comment "\begin{comment} ... \end{comment} block"
\begin{comment}
	${0}
\end{comment}
endsnippet
snippet equation "\begin{equation} ... \end{equation} block"
\begin{equation}
	${0}
\end{equation}
endsnippet
snippet minted "\begin{minted} ... \end{minted} block"
\begin{minted}
${0}
\end{minted}
endsnippet
snippet verbatim "\begin{verbatim} ... \end{verbatim} block"
\begin{verbatim}
${0}
\end{verbatim}
endsnippet
snippet tabular "\begin{tabular} ... \end{tabular} block"
\begin{tabular}{${2:c}}
	${0}
\end{tabular}
endsnippet
snippet enumerate "\begin{enumerate} ... \end{enumerate} block"
\begin{enumerate}
	${0}
\end{enumerate}
endsnippet
snippet enum "\begin{enumerate} ... \end{enumerate} block"
\begin{enumerate}
	${0}
\end{enumerate}
endsnippet
snippet enuma "enumerate environment with (a)(b)(c)."
\begin{enumerate}[(a)]
	${0}
\end{enumerate}
endsnippet
snippet item "\begin{itemize} ... \end{itemize} block"
\begin{itemize}
	\item ${0}
\end{itemize}
endsnippet
snippet outline "\begin{outline} ... \end{outline} (package outlines)"
\begin{outline}[itemize]
	\1 ${0}
\end{outline}
endsnippet
snippet minipage "\begin{minipage} ... \end{minipage} block"
\begin{minipage}[t]{\linewidth}
	${0}
\end{minipage}
endsnippet
snippet cases "\begin{cases} ... \end{cases} block"
\begin{cases}
	${1}    & \text{ if }  ${2} \\\\
	${3}    & \text{ otherwise}
\end{cases}$0
endsnippet
snippet pmatrix "2X2 pmatrix (with round brackets)"
\begin{pmatrix}
	${1}  &  ${2} \\\\
	${3}  &  ${4}
\end{pmatrix}
endsnippet
snippet bmatrix "2X2 bmatrix (with right brackets)"
\begin{bmatrix}
	${1}  &  ${2} \\\\
	${3}  &  ${4}
\end{bmatrix}
endsnippet
snippet matrix "2X2 matrix (or other)"
\begin{${1:/p/b/v/V/B/small}matrix}
	${2:A}  &  ${3:B} \\\\
	${4:C}  &  ${5:D}
\end{$1matrix}
endsnippet


# ===================
# Figure, Table, etc.
# ===================
snippet includegraphics
\includegraphics[width=\linewidth]{${1:filename.png}}
endsnippet
snippet figure
\begin{figure}[htb]
	\centering
	\includegraphics[width=\linewidth]{${1:filename.png}}
	\caption{${2:Caption here}}
	\label{fig:${3:figure1}}
\end{figure}
endsnippet
snippet subfigure
\begin{figure}[h!]
	\centering
	\begin{subfigure}[b]{0.45\linewidth}
		\centering
		${2:% includegraphics Here}
		\caption{First Subfigure}
	\end{subfigure}
	\hfill
	\begin{subfigure}[b]{0.45\linewidth}
		\centering
		${3:% Figure Here}
		\caption{Second Subfigure}
	\end{subfigure}
\end{figure}
endsnippet
snippet newcolumntype  "Use a narrow column width for table."
\newcolumntype{P}[1]{>{\centering\arraybackslash}p{#1}}
%\setlength\tabcolsep{2pt}  % default value: 6pt
endsnippet


# Symbols
# =======
snippet cmark  "Define \cmark (check mark) symbol: ✔"
\usepackage{pifont}
\newcommand{\cmark}{\ding{51}}%
endsnippet
snippet xmark  "Define \xmark (cross mark) symbol: ✗"
\usepackage{pifont}
\newcommand{\xmark}{\ding{55}}%
endsnippet
snippet minus
\newcommand{\minus}{\scalebox{0.75}[1.0]{$-$}}
endsnippet


# Miscellaneous
# =============
snippet hr "A full-width horizontal rule"
% a rule (line) spanning the entire width of the page
\makebox[\linewidth]{\rule{\paperwidth}{1.0pt}}

endsnippet
